home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / rip2 / rip.c < prev    next >
C/C++ Source or Header  |  1993-09-28  |  34KB  |  1,155 lines

  1. /* This file contains code to implement the Routing Information Protocol (RIP)
  2.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  3.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  4.  * credited. (Well, here's some credit :-). AGB 4-28-88
  5.  
  6.  * Further documentation on the RIP protocol is now available in Charles
  7.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  8.  *
  9.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  10.  *
  11.  * Code gutted and substantially rewritten. KA9Q 9/89
  12.  *
  13.  * Mods by PA0GRI
  14.  *
  15.  *    Changes Copyright (c) 1993 Jeff White - N0POY, All Rights Reserved.
  16.  *    Permission granted for non-commercial copying and use, provided
  17.  *    this notice is retained.
  18.  *
  19.  * Rehack for RIP-2 (RFC1388) by N0POY 4/1993
  20.  *
  21.  * Beta release 9/8/93 V0.91
  22.  *
  23.  */
  24.  
  25. #include <stdarg.h>
  26. #include <ctype.h>
  27. #include <time.h>
  28. #include "global.h"
  29. #include "config.h"
  30. #include "mbuf.h"
  31. #include "netuser.h"
  32. #include "udp.h"
  33. #include "timer.h"
  34. #include "iface.h"
  35. #include "ip.h"
  36. #include "internet.h"
  37. #include "rip.h"
  38. #include "arp.h"
  39. #include "socket.h"
  40.  
  41. #ifdef RIP
  42.  
  43. struct rip_stat Rip_stat;
  44. int16 Rip_trace;
  45. FILE *Rip_trace_file = NULLFILE;
  46. char *Rip_trace_fname = NULLCHAR;
  47. int16 Rip_merge;
  48. int32 Rip_ttl = RIP_TTL;
  49. int16 Rip_ver_refuse = 0;
  50. int16 Rip_default_refuse = FALSE;
  51. struct rip_list *Rip_list;
  52. struct udp_cb *Rip_cb;
  53. struct rip_auth *Rip_auth;
  54. struct rip_refuse *Rip_refuse;
  55. char Rip_nullpass[RIP_AUTH_SIZE];
  56.  
  57. static void rip_rx __ARGS((struct iface *iface,struct udp_cb *sock,int cnt));
  58. static void proc_rip __ARGS((struct iface *iface,int32 gateway,
  59.     struct rip_route *ep,unsigned char version));
  60. static char *putheader __ARGS((char *cp,char command,char version,int16 domain));
  61. static char *putentry __ARGS((char *cp,int16 fam,int16 tag,int32 target,
  62.    int32 targmask,int32 router,int32 metric));
  63. static void send_routes __ARGS((int32 dest,int16 port,int trig,
  64.     int flags,char version, struct rip_list *rdata));
  65. static void pullauthentication __ARGS((struct rip_authenticate *ep, struct mbuf **bpp));
  66. static void pullheader __ARGS((struct rip_head *ep, struct mbuf **bpp));
  67. static int check_authentication __ARGS((struct rip_auth *auth,
  68.    struct mbuf **bpp, struct rip_head *header, int32 srcaddr, char *ifcname,
  69.    struct rip_authenticate *entry));
  70. static char *putauth  __ARGS((char *cp, int16 authtype,
  71.    char *authpass));
  72. static void rip_trace(short level, char *errstr, ...);
  73.  
  74. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  75.  
  76. void
  77. rip_shout(p)
  78. void *p;
  79. {
  80.     register struct rip_list *rl;
  81.  
  82.     rl = (struct rip_list *)p;
  83.     stop_timer(&rl->rip_time);
  84.     send_routes(rl->dest,RIP_PORT,0,rl->flags,rl->rip_version,rl);
  85.     set_timer(&rl->rip_time,rl->interval*1000L);
  86.     start_timer(&rl->rip_time);
  87. }
  88.  
  89. /* Send the routing table. */
  90. static void
  91. send_routes(dest,port,trig,flags,version,rdata)
  92. int32 dest;                   /* IP destination address to send to */
  93. int16 port;
  94. int trig;                     /* Send only triggered updates? */
  95. int flags;
  96. char version;                 /* Version of RIP packet */
  97. struct rip_list *rdata;       /* Used for RIP-2 packets */
  98. {
  99.    char *cp;
  100.    int i,bits,numroutes,maxroutes;
  101.    int16 pktsize;
  102.    struct mbuf *bp;
  103.    struct route *rp;
  104.    struct socket lsock,fsock;
  105.    struct iface *iface;
  106.  
  107.    if((rp = rt_lookup(dest)) == NULLROUTE) {
  108.       rip_trace(1, "No route to [%s] exists, cannot send", inet_ntoa(dest));
  109.       return;                 /* No route exists, can't do it */
  110.    }
  111.    iface = rp->iface;
  112.  
  113.    /* Compute maximum packet size and number of routes we can send */
  114.    pktsize = ip_mtu(dest) - IPLEN;
  115.    pktsize = min(pktsize,RIP_PKTSIZE);
  116.    maxroutes = (pktsize - RIP_HEADER) / RIP_ENTRY;
  117.    
  118.    lsock.address = INADDR_ANY;
  119.    lsock.port = RIP_PORT;
  120.    fsock.address = dest;
  121.    fsock.port = port;
  122.  
  123.    /* Allocate space for a full size RIP packet and generate header */
  124.    if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  125.       return; 
  126.    numroutes = 0;
  127.  
  128.    /* See if we know information about what to send out */
  129.  
  130.    if ((version >= RIP_VERSION_2) && (rdata != NULLRL)) {
  131.       cp = putheader(bp->data,RIPCMD_RESPONSE, version, rdata->domain);
  132.       /* See if we need to put an authentication header on */
  133.       if (flags & RIP_AUTHENTICATE) {
  134.          cp = putauth(cp, RIP_AUTH_SIMPLE, rdata->rip_auth_code);
  135.          numroutes++;
  136.       }
  137.    } else {
  138.       cp = putheader(bp->data,RIPCMD_RESPONSE, version, 0);
  139.    }
  140.  
  141.    /* Emit route to ourselves, if requested */
  142.    if(flags & RIP_US) {
  143.       if (version == RIP_VERSION_1)
  144.          cp = putentry(cp,RIP_AF_INET,0,iface->addr,0,0,1);
  145.       else
  146.          cp = putentry(cp,RIP_AF_INET,0,iface->addr,0xFFFFFFFF,0,1);
  147.       numroutes++;
  148.    }
  149.  
  150.    /* Emit default route, if appropriate */
  151.  
  152.    if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)
  153.     && (!trig || (R_default.flags & RTTRIG))){
  154.       if(!(flags & RIP_SPLIT) || iface != R_default.iface){
  155.          if (version == RIP_VERSION_1)
  156.             cp = putentry(cp,RIP_AF_INET,0,0,0,0,R_default.metric);
  157.          else
  158.                 cp = putentry(cp,RIP_AF_INET,R_default.route_tag,0,0,0,R_default.metric);
  159.          numroutes++;
  160.       } else if (trig && (flags & RIP_POISON)) {
  161.          /* Poisoned reverse */
  162.          if (version == RIP_VERSION_1)
  163.                cp = putentry(cp,RIP_AF_INET,0,0,0,0,RIP_METRIC_UNREACHABLE);
  164.          else
  165.                 cp = putentry(cp,RIP_AF_INET,R_default.route_tag,0,0,0,
  166.                RIP_METRIC_UNREACHABLE);
  167.          numroutes++;
  168.       }
  169.    }
  170.  
  171.    for(bits=0;bits<32;bits++){
  172.       for(i=0;i<HASHMOD;i++){
  173.          for(rp = Routes[bits][i];rp != NULLROUTE;rp=rp->next){
  174.             if((rp->flags & RTPRIVATE)
  175.              || (trig && !(rp->flags & RTTRIG))) 
  176.                continue;
  177.  
  178.             if(numroutes >= maxroutes){
  179.                /* Packet full, flush and make another */
  180.                bp->cnt = RIP_HEADER + numroutes * RIP_ENTRY;
  181.                send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  182.                Rip_stat.vdata[version].output++;
  183.                if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  184.                   return; 
  185.                numroutes = 0;
  186.  
  187.                if (version >= RIP_VERSION_2 && rdata != NULLRL) {
  188.                   cp = putheader(bp->data,RIPCMD_RESPONSE, version,
  189.                      rdata->domain);
  190.                   /* See if we need to put an authentication header on */
  191.                   if (flags & RIP_AUTHENTICATE) {
  192.                      cp = putauth(cp, RIP_AUTH_SIMPLE, rdata->rip_auth_code);
  193.                      numroutes++;
  194.                   }
  195.                } else {
  196.                   cp = putheader(bp->data,RIPCMD_RESPONSE, version, 0);
  197.                }
  198.                 }
  199.  
  200.             if(!(rp->flags & RIP_SPLIT) || iface != rp->iface){
  201.                if (version == RIP_VERSION_1)
  202.                   cp = putentry(cp,RIP_AF_INET,0,rp->target,0,0,rp->metric);
  203.                else
  204.                   cp = putentry(cp,RIP_AF_INET,rp->route_tag,rp->target,
  205.                      (0xFFFFFFFF << (32 - rp->bits)),rdata->proxy_route,
  206.                      rp->metric);
  207.                numroutes++;
  208.             } else if(trig && (flags & RIP_POISON)) {
  209.                if (version == RIP_VERSION_1)
  210.                   cp = putentry(cp,RIP_AF_INET,0,rp->target,0,0,RIP_METRIC_UNREACHABLE);
  211.                else
  212.                   cp = putentry(cp,RIP_AF_INET,rp->route_tag,rp->target,
  213.                      (0xFFFFFFFF << (32 - rp->bits)),rdata->proxy_route,
  214.                      RIP_METRIC_UNREACHABLE);
  215.                numroutes++;
  216.             }
  217.          }
  218.       }
  219.    }
  220.    if(numroutes != 0){
  221.       bp->cnt = RIP_HEADER + numroutes * RIP_ENTRY;
  222.       send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  223.       Rip_stat.vdata[version].output++;
  224.    } else {
  225.       free_p(bp);
  226.    }
  227. }
  228.  
  229. /* Add an entry to the rip broadcast list */
  230.  
  231. int
  232. rip_add(dest,interval,flags,version,authpass,domain,route_tag,proxy)
  233. int32 dest;
  234. int32 interval;
  235. char flags;
  236. char version;
  237. char authpass[RIP_AUTH_SIZE];
  238. int16 domain;
  239. int16 route_tag;
  240. int32 proxy;
  241. {
  242.    register struct rip_list *rl;
  243.    struct route *rp;
  244.  
  245.    for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  246.       if((rl->dest == dest) && (rl->domain == domain))
  247.          return 0;
  248.  
  249.    if((rp = rt_lookup(dest)) == NULLROUTE){
  250.       tprintf("%s is unreachable\n",inet_ntoa(dest));
  251.       return 0;
  252.    }
  253.  
  254.    /* get a chunk of memory for the rip interface descriptor */
  255.    rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  256.  
  257.    /* tack this record on as the first in the list */
  258.    rl->next = Rip_list;
  259.    if(rl->next != NULLRL)
  260.       rl->next->prev = rl;
  261.    Rip_list = rl;
  262.  
  263.    rl->dest = dest;
  264.  
  265.    rip_trace(9, "Rip added V%d Flags %d Tag %d Proxy %s Domain %d Auth %s Interval %d",
  266.       version, flags, route_tag, inet_ntoa(proxy), domain, authpass, interval);
  267.  
  268.    /* and the interface ptr, tick interval and flags */
  269.    rl->iface = rp->iface;
  270.    rl->rip_version = version;
  271.    rl->interval = interval;
  272.    rl->flags = flags;
  273.    rl->proxy_route = proxy;
  274.    rl->route_tag = route_tag;
  275.    rl->domain = domain;
  276.    memcpy(rl->rip_auth_code,authpass,RIP_AUTH_SIZE);
  277.  
  278.    /* and set up the timer stuff */
  279.    set_timer(&rl->rip_time,interval*1000L);
  280.    rl->rip_time.func = rip_shout;
  281.    rl->rip_time.arg = rl;
  282.    start_timer(&rl->rip_time);
  283.    return 1;
  284. }
  285.  
  286. /* add a gateway to the rip_refuse list which allows us to ignore their
  287.  * advertisements
  288.  */
  289.  
  290. int
  291. riprefadd(gateway)
  292. int32 gateway;
  293. {
  294.    register struct rip_refuse *rl;
  295.  
  296.    for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  297.       if(rl->target == gateway)
  298.          return 0;         /* Already in table */
  299.   
  300.    /* get a chunk of memory for the rip interface descriptor */
  301.    rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  302.  
  303.    /* tack this record on as the first in the list */
  304.    rl->next = Rip_refuse;
  305.    if(rl->next != NULLREF)
  306.       rl->next->prev = rl;
  307.    Rip_refuse = rl;
  308.  
  309.    /* fill in the gateway to ignore */
  310.    rl->target = gateway;
  311.    return 0;
  312. }
  313.  
  314. /* Add an authentication type to an interface name */
  315.  
  316. int
  317. ripauthadd(ifcname, domain, password)
  318. char *ifcname;
  319. int16 domain;
  320. char *password;
  321. {
  322.    register struct rip_auth *ra;
  323.    char *name;
  324.    int x;
  325.  
  326.    for(ra = Rip_auth; ra != NULLAUTH; ra = ra->next)
  327.       if(!strcmp(ifcname,ra->ifc_name) && (ra->domain == domain))
  328.          return 1;         /* Already in table */
  329.   
  330.    /* get a chunk of memory for the rip interface descriptor */
  331.    ra = (struct rip_auth *)callocw(1,sizeof(struct rip_auth));
  332.  
  333.    /* tack this record on as the first in the list */
  334.    ra->next = Rip_auth;
  335.    if(ra->next != NULLAUTH)
  336.       ra->next->prev = ra;
  337.    Rip_auth = ra;
  338.  
  339.    /* fill in the data */
  340.    ra->ifc_name = mallocw(strlen(ifcname)+1);
  341.    strcpy(ra->ifc_name, ifcname);
  342.    ra->domain = domain;
  343.    for (x = 0; x < RIP_AUTH_SIZE+1; x++)
  344.       ra->rip_auth_code[x] = '\0';
  345.    strcpy(ra->rip_auth_code, password);
  346.    return 0;
  347. }
  348.  
  349. /* Drop an authentication to an interface name */
  350.  
  351. int
  352. ripauthdrop(ifcname, domain)
  353. char *ifcname;
  354. int16 domain;
  355. {
  356.    register struct rip_auth *ra;
  357.    char *name;
  358.  
  359.    for(ra = Rip_auth; ra != NULLAUTH; ra = ra->next)
  360.       if(!strcmp(ifcname,ra->ifc_name) && (ra->domain == domain))
  361.          break;
  362.   
  363.    /* leave if we didn't find it */
  364.    if(ra == NULLAUTH)
  365.       return 0;
  366.  
  367.    /* Unlink from list */
  368.    if(ra->next != NULLAUTH)
  369.       ra->next->prev = ra->prev;
  370.    if(ra->prev != NULLAUTH)
  371.       ra->prev->next = ra->next;
  372.    else
  373.       Rip_auth = ra->next;
  374.  
  375.    free((char *)ra->ifc_name);
  376.    free((char *)ra);
  377.    return 0;
  378. }
  379.  
  380. /* drop a RIP target */
  381.  
  382. int
  383. rip_drop(dest,domain)
  384. int32    dest;
  385. int16 domain;
  386. {
  387.    register struct rip_list *rl;
  388.  
  389.    for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  390.       if((rl->dest == dest) && (rl->domain == domain))
  391.          break;
  392.  
  393.    /* leave if we didn't find it */
  394.    if(rl == NULLRL)
  395.       return 0;
  396.  
  397.    /* stop the timer */
  398.    stop_timer(&rl->rip_time);
  399.  
  400.    /* Unlink from list */
  401.    if(rl->next != NULLRL)
  402.       rl->next->prev = rl->prev;
  403.    if(rl->prev != NULLRL)
  404.       rl->prev->next = rl->next;
  405.    else
  406.       Rip_list = rl->next;
  407.  
  408.    /* and deallocate the descriptor memory */
  409.    free((char *)rl);
  410.    return 0;
  411. }
  412.  
  413. /* drop a RIP-refuse target from the rip_refuse list */
  414.  
  415. int
  416. riprefdrop(gateway)
  417. int32 gateway;
  418. {
  419.    register struct rip_refuse *rl;
  420.     
  421.    for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  422.       if(rl->target == gateway)
  423.          break;
  424.   
  425.    /* leave if we didn't find it */
  426.    if(rl == NULLREF)
  427.       return 0;
  428.  
  429.    /* Unlink from list */
  430.    if(rl->next != NULLREF)
  431.       rl->next->prev = rl->prev;
  432.    if(rl->prev != NULLREF)
  433.       rl->prev->next = rl->next;
  434.    else
  435.       Rip_refuse = rl->next;
  436.  
  437.    /* and deallocate the structure memory */
  438.    free((char *)rl);
  439.    return 0;
  440. }
  441.  
  442. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  443.  
  444. void
  445. rip_trigger()
  446. {
  447.    register struct rip_list *rl;
  448.    int bits,i;
  449.    struct route *rp;
  450.  
  451.    for(rl=Rip_list;rl != NULLRL;rl = rl->next){
  452.       send_routes(rl->dest,RIP_PORT,1,rl->flags,rl->rip_version,rl);
  453.    }
  454.    /* Clear the trigger list */
  455.    R_default.flags &= ~RTTRIG;
  456.    for(bits=0;bits<32;bits++){
  457.       for(i=0;i<HASHMOD;i++){
  458.          for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  459.             rp->flags &= ~RTTRIG;
  460.          }
  461.       }
  462.    }
  463. }
  464.  
  465. /* Start RIP agent listening at local RIP UDP port */
  466. int
  467. rip_init()
  468. {
  469.    struct socket lsock;
  470.    int x;
  471.  
  472.    lsock.address = INADDR_ANY;
  473.    lsock.port = RIP_PORT;
  474.  
  475.    if(Rip_cb == NULLUDP)
  476.       Rip_cb = open_udp(&lsock,rip_rx);
  477.  
  478.    for (x = 0; x < RIP_AUTH_SIZE; x++)
  479.       Rip_nullpass[x] = 0;
  480.  
  481.    Rip_trace = 0;
  482.  
  483.    /* Add the 0 domain with no password */
  484.    
  485.    ripauthadd(DEFAULTIFC, 0, RIP_NO_AUTH);
  486.  
  487.    return 0;
  488. }
  489.  
  490. /* Process RIP input received from 'interface'. */
  491. static void
  492. rip_rx(iface,sock,cnt)
  493. struct iface *iface;
  494. struct udp_cb *sock;
  495. int cnt;
  496. {
  497.    struct mbuf *bp;
  498.    struct socket fsock;
  499.    struct rip_refuse *rfl;
  500.    struct rip_route entry;
  501.    struct rip_head header;
  502.    struct route *rp;
  503.    struct rip_list *rl;
  504.  
  505.    /* receive the RIP packet */
  506.    recv_udp(sock,&fsock,&bp);
  507.  
  508.    /* check the gateway of this packet against the rip_refuse list and
  509.     * discard it if a match is found
  510.     */
  511.  
  512.    for(rfl=Rip_refuse;rfl != NULLREF;rfl = rfl->next){
  513.       if(fsock.address == rfl->target){
  514.          Rip_stat.refusals++;
  515.          rip_trace(2, "RIP refused from %s",inet_ntoa(fsock.address));
  516.          free_p(bp);
  517.          return;
  518.       }
  519.    }
  520.  
  521.    pullheader(&header, &bp);
  522.  
  523.    /* increment the rcvd cnt */
  524.    Rip_stat.vdata[header.rip_vers].rcvd++;
  525.  
  526.    /* Check to see if we'll accept this version on this interface */
  527.  
  528.    if (header.rip_vers <= Rip_ver_refuse) {
  529.       rip_trace(3, "RIP version %d refused from [%s]", header.rip_vers,
  530.          inet_ntoa(fsock.address));
  531.       Rip_stat.refusals++;
  532.       free_p(bp);
  533.       return;
  534.    }
  535.  
  536.     /* Check the version of the frame */
  537.    switch (header.rip_vers) {
  538.       case RIP_VERSION_2 :
  539.          break;
  540.  
  541.       case RIP_VERSION_0 :
  542.          rip_trace(1, "RIP Version 0 refused from [%s]", inet_ntoa(fsock.address));
  543.          Rip_stat.version++;
  544.          free_p(bp);
  545.          return;
  546.  
  547.       case RIP_VERSION_1 :
  548.          /* Toss RIP if header is bogus for V1 */
  549.          if (header.rip_domain != 0) {
  550.             rip_trace(1, "RIP-1 bogus header, data in null fields from [%s]",
  551.                inet_ntoa(fsock.address));
  552.             Rip_stat.vdata[RIP_VERSION_1].unknown++;
  553.             free_p(bp);
  554.             return;
  555.          }
  556.          break;
  557.    }
  558.  
  559.    rip_trace(2, "RIP Packet version %d processing",header.rip_vers);
  560.  
  561.     switch(header.rip_cmd){
  562.     case RIPCMD_RESPONSE:
  563.       rip_trace(2, "RIPCMD_RESPONSE from [%s] domain %d",inet_ntoa(fsock.address),
  564.          header.rip_domain);
  565.  
  566.         Rip_stat.vdata[header.rip_vers].response++;
  567.         pullentry(&entry,&bp);
  568.  
  569.       if (header.rip_vers >= RIP_VERSION_2) {
  570.          /* We still have the authentication entry from above */
  571.  
  572.          if (!check_authentication(Rip_auth, &bp, &header,fsock.address,
  573.              iface->name, (struct rip_authenticate *)&entry)) {
  574.             free_p(bp);
  575.             return;
  576.          }
  577.       }
  578.       proc_rip(iface,fsock.address,&entry,header.rip_vers);
  579.  
  580.       while(len_p(bp) >= RIP_ENTRY){
  581.          pullentry(&entry,&bp);
  582.          proc_rip(iface,fsock.address,&entry,header.rip_vers);
  583.       }
  584.  
  585.         /* If we can't reach the sender of this update, or if
  586.          * our existing route is not through the interface we
  587.          * got this update on, add him as a host specific entry
  588.          */
  589.         if((rp = rt_blookup(fsock.address,32)) != NULLROUTE){
  590.             /* Host-specific route already exists, refresh it */
  591.             start_timer(&rp->timer);
  592.         } else if((rp = rt_lookup(fsock.address)) == NULLROUTE
  593.                   || rp->iface != iface) {
  594.                entry.rip_family = RIP_AF_INET;
  595.             entry.rip_tag = 0;
  596.                entry.rip_dest = fsock.address;
  597.             if (header.rip_vers > RIP_VERSION_1)
  598.                entry.rip_dest_mask = 32;
  599.             else
  600.                entry.rip_dest_mask = 0;
  601.             entry.rip_router = 0;
  602.                entry.rip_metric = 0;       /* will get incremented to 1 */
  603.                proc_rip(iface,fsock.address,&entry,header.rip_vers);
  604.         }
  605.         if(Rip_merge)
  606.             rt_merge(Rip_trace);
  607.         rip_trigger();
  608.         break;
  609.  
  610.     case RIPCMD_REQUEST:
  611.       rip_trace(2, "RIPCMD_REQUEST from [%s] domain %d",inet_ntoa(fsock.address),
  612.          header.rip_domain);
  613.  
  614.         Rip_stat.vdata[header.rip_vers].request++;
  615.         /* For now, just send the whole table with split horizon
  616.          * enabled when the source port is RIP_PORT, and send
  617.          * the whole table with split horizon disable when another
  618.          * source port is used. This should be replaced with a more
  619.          * complete implementation that checks for non-global requests
  620.          */
  621.  
  622.       if (header.rip_vers > RIP_VERSION_1) {
  623.          /* RIP-2, let's see if we know something about this guy */
  624.          rp = rt_lookup(fsock.address);
  625.          for (rl = Rip_list; rl != NULLRL; rl = rl->next)
  626.             if ((rl->dest == rp->target) && (rl->domain == header.rip_domain))
  627.                break;
  628.  
  629.          if (rl == NULLRL)
  630.             if (fsock.port == RIP_PORT)
  631.                send_routes(fsock.address,fsock.port,0,(RIP_BROADCAST & RIP_SPLIT &
  632.                   RIP_POISON),header.rip_vers,NULLRL);
  633.             else
  634.                send_routes(fsock.address,fsock.port,0,(RIP_BROADCAST),
  635.                   header.rip_vers,NULLRL);
  636.          else
  637.             if (fsock.port == RIP_PORT)
  638.                send_routes(fsock.address,fsock.port,0,rl->flags,header.rip_vers,rl);
  639.             else
  640.                send_routes(fsock.address,fsock.port,0,(rl->flags & ~(RIP_SPLIT | RIP_POISON)),
  641.                   header.rip_vers,rl);
  642.       } else {
  643.            if(fsock.port == RIP_PORT)
  644.                send_routes(fsock.address,fsock.port,0,(RIP_SPLIT & RIP_BROADCAST & RIP_POISON),
  645.                header.rip_vers,NULLRL);
  646.            else
  647.                send_routes(fsock.address,fsock.port,0,RIP_BROADCAST,
  648.                header.rip_vers,NULLRL);
  649.       }
  650.       break;
  651.  
  652.     default:
  653.       rip_trace(1, "RIPCMD Unknown or not implemented from [%s] command %d",
  654.          inet_ntoa(fsock.address),header.rip_cmd);
  655.         Rip_stat.vdata[header.rip_vers].unknown++;
  656.         break;
  657.     } /* switch */
  658.     free_p(bp);
  659. }
  660.  
  661. /* Apply a set of heuristics for determining the number of significant bits
  662.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  663.  * include the address mask for each entry.  Applies only to RIP-1 packets.
  664.  */
  665.  
  666. int
  667. nbits(target)
  668. int32 target;
  669. {
  670.    int bits;
  671.  
  672.    if(target == 0)
  673.       return 0;   /* Special case: 0.0.0.0 is the default route */
  674.  
  675.    /* Check the host-part bytes of
  676.     * the address to check for byte-wide zeros
  677.     * which we'll consider to be subnet routes.
  678.     * e.g.    44.80.0.0 will be considered to be equal to 44.80/16
  679.     * whereas 44.80.1.0 will be considered to be 44.80.1/24
  680.     */
  681.    switch (hibyte(hiword(target)) >> 6) {
  682.    case 3:     /* Class C address */
  683.       /*is it a host address ? i.e. are there any 1's in the
  684.        * host part ?
  685.        */
  686.       if(target & 0xff)
  687.          bits = 32;
  688.       else
  689.          bits = 24;
  690.       break;
  691.    case 2:     /* Class B address */
  692.       if(target & 0xff)
  693.          bits = 32;
  694.       else if(target & 0xff00)
  695.          bits = 24;
  696.       else
  697.          bits = 16;
  698.       break;
  699.    case 0:     /* Class A address */
  700.    case 1:
  701.       if(target & 0xff)
  702.          bits = 32;
  703.       else if(target & 0xff00)
  704.          bits = 24;
  705.       else if(target & 0xff0000)
  706.          bits = 16;
  707.       else
  708.          bits = 8;
  709.    }
  710.  
  711.    return bits;
  712. }
  713.  
  714. /* Remove and process a RIP response entry from a packet */
  715.  
  716. static void
  717. proc_rip(iface,gateway,ep,version)
  718. struct iface *iface;
  719. int32 gateway;
  720. register struct rip_route *ep;
  721. unsigned char version;
  722. {
  723.    int32 interval;
  724.    int32 target;
  725.    unsigned int bits;
  726.    register struct route *rp;
  727.    struct rip_list *rl;
  728.    int add = 0;   /* action flags */
  729.    int drop = 0;
  730.    int trigger = 0;
  731.  
  732.    if(ep->rip_family != RIP_AF_INET) {
  733.       if (ep->rip_family == RIP_AF_AUTH)
  734.          return;
  735.       /* Skip non-IP addresses */
  736.       rip_trace(1, "RIP_rx: Not an IP family packet\n");
  737.       Rip_stat.addr_family++;
  738.       return;
  739.    }
  740.  
  741.    /* RIP-1 says all unused fields must be zero */
  742.    if (version == RIP_VERSION_1) {
  743.       if (ep->rip_tag != 0 || ep->rip_dest_mask != 0 || ep->rip_router != 0) {
  744.          rip_trace(1,"RIP_rx: RIP-1 entry bad, data in null fields");
  745.          Rip_stat.vdata[version].unknown++;
  746.       }
  747.        /* Guess at the mask, since it's not explicit for RIP-1 */
  748.        bits = nbits(ep->rip_dest);
  749.       target = ep->rip_dest;
  750.    } else {
  751.       /* Assume RIP-2 */
  752.       if (!ep->rip_dest_mask) {
  753.          /* No netmask, guess */
  754.           bits = nbits(ep->rip_dest);
  755.       } else {
  756.          bits = mask2width(ep->rip_dest_mask);
  757.       }
  758.       target = ep->rip_dest;
  759.       /* Check for "proxy" rip */
  760.       if (ep->rip_router) {
  761.          rip_trace(3, "Proxy rip pointing to [%s]", inet_ntoa(ep->rip_router));
  762.          gateway = ep->rip_router;
  763.       } 
  764.    }
  765.  
  766.    /* Don't ever add a route to myself through somebody! */
  767.    if(bits == 32 && ismyaddr(target) != NULLIF) {
  768.       rip_trace(2, "Route to self [%s]/32 metric %lu", inet_ntoa(target),
  769.          ep->rip_metric);
  770.       return;
  771.    }
  772.  
  773.    /* Check to see if we'll take a default route, zero bits mean default */
  774.  
  775.    if (Rip_default_refuse && bits == 0) {
  776.       rip_trace(2, "Default route refused from [%s]", inet_ntoa(target));
  777.       return;
  778.    }
  779.  
  780.    /* Update metric to reflect link cost */
  781.    ep->rip_metric++;
  782.    ep->rip_metric = min(ep->rip_metric,RIP_METRIC_UNREACHABLE);
  783.  
  784.    /* Find existing entry, if any */
  785.    rp = rt_blookup(target,bits);
  786.  
  787.    /* Don't touch private routes */
  788.    if(rp != NULLROUTE && (rp->flags & RTPRIVATE)) {
  789.       rip_trace(3, "Route to [%s]/%u unchanged, private", inet_ntoa(target),
  790.          bits);
  791.       return;
  792.    }
  793.  
  794.    if(rp == NULLROUTE) {
  795.       if(ep->rip_metric < RIP_METRIC_UNREACHABLE) {
  796.          /* New route; add it and trigger an update */
  797.          add++;
  798.          trigger++;
  799.       }
  800.    } else if(rp->metric == RIP_METRIC_UNREACHABLE) {
  801.       /* Route is in hold-down; ignore this guy */
  802.       rip_trace(2, "Route to [%s]/%u ignored (hold-down) metric %lu",
  803.              inet_ntoa(target), bits, ep->rip_metric);
  804.    } else if(rp->gateway == gateway && rp->iface == iface) {
  805.       /* This is the gateway for the entry we already have;
  806.        * restart the timer
  807.        */
  808.       start_timer(&rp->timer);
  809.       if(rp->metric != ep->rip_metric) {
  810.          /* Metric has changed. Update it and trigger an
  811.           * update. If route has become unavailable, start
  812.           * the hold-down timeout.
  813.           */
  814.          rip_trace(3, "Metric change [%s]/%u %lu -> %lu", inet_ntoa(target),
  815.             bits, rp->metric, ep->rip_metric);
  816.          if(ep->rip_metric == RIP_METRIC_UNREACHABLE)
  817.             rt_timeout(rp);      /* Enter hold-down timeout */
  818.          else
  819.             rp->metric = ep->rip_metric;
  820.          trigger++;
  821.       }
  822.    } else {
  823.       /* Entry is from a different gateway than the current route */
  824.       if(ep->rip_metric < rp->metric) {
  825.          /* Switch to a new gateway */
  826.          rip_trace(3, "Metric better [%s]/%u new: %lu old: %lu", inet_ntoa(target),
  827.             bits, ep->rip_metric, rp->metric);
  828.          drop++;
  829.          add++;
  830.          trigger++;
  831.       } else {
  832.          /* Metric is no better, stay with current route */
  833.          rip_trace(3, "Metric not better [%s]/%u new: %lu old: %lu", inet_ntoa(target),
  834.             bits, ep->rip_metric, rp->metric);
  835.       }
  836.    }
  837.    if(drop) {
  838.       /* Switching to a better gateway; delete old entry */
  839.  
  840.       rip_trace(2, "Route drop [%s]/%u", inet_ntoa(target), bits);
  841.       rt_drop(target,bits);
  842.    }
  843.  
  844.    if(add) {
  845.       /* Add a new entry */
  846.       interval = Rip_ttl;
  847.       for(rl=Rip_list; rl != NULLRL; rl = rl->next){
  848.          if(rl->iface == iface){
  849.             interval = rl->interval * 4;
  850.             break;
  851.          }
  852.       }
  853.       rip_trace(2, "Route add [%s]/%u through %s via ",
  854.          inet_ntoa(target), bits, iface->name);
  855.       rip_trace(2, "[%s] metric %lu", inet_ntoa(gateway),
  856.          ep->rip_metric);
  857.  
  858.       rp = rt_add(target,(unsigned) bits,gateway,iface,
  859.                   (int) ep->rip_metric,interval,0);
  860.  
  861.       /* Add in the routing tag for RIP-2 */
  862.  
  863.       if (version >= RIP_VERSION_2)
  864.          rp->route_tag = ep->rip_tag;
  865.       else
  866.          rp->route_tag = 0;
  867.    }
  868.    /* If the route changed, mark it for a triggered update */
  869.    if(trigger){
  870.       rp->flags |= RTTRIG;
  871.    }
  872. }
  873.  
  874. /* Send a RIP request packet to the specified destination */
  875.  
  876. int
  877. ripreq(dest,replyport,version)
  878. int32 dest;
  879. int16 replyport;
  880. int16 version;
  881. {
  882.    struct mbuf *bp;
  883.    struct socket lsock,fsock;
  884.    char *cp;
  885.    register struct rip_list *rl;
  886.  
  887.    lsock.address = INADDR_ANY;
  888.    lsock.port = replyport;
  889.  
  890.    /* if we were given a valid dest addr, ask it (the routers on that net)
  891.     * for a default gateway
  892.     */
  893.  
  894.    if(dest == 0)
  895.       return 0;
  896.  
  897.    fsock.address = dest;
  898.    fsock.port = RIP_PORT;
  899.  
  900.    /* Send out one RIP Request packet as a broadcast to 'dest'  */
  901.    if((bp = alloc_mbuf(RIP_HEADER + RIP_ENTRY)) == NULLBUF)
  902.       return -1;
  903.  
  904.    /* Check to see if we already know something about who we're   */
  905.    /* requesting the RIP from */
  906.  
  907.    for (rl = Rip_list; rl != NULLRL; rl = rl->next)
  908.       if (rl->dest == dest)
  909.          break;
  910.  
  911.    bp->cnt = RIP_HEADER + RIP_ENTRY;
  912.    if (rl != NULLRL) {
  913.       cp = putheader(bp->data,RIPCMD_REQUEST,rl->rip_version, rl->domain);
  914.       if (rl->rip_version >= RIP_VERSION_2) {
  915.          if (rl->flags & RIP_AUTHENTICATE) {
  916.             cp = putauth(cp,RIP_AUTH_SIMPLE,rl->rip_auth_code);
  917.             bp->cnt += RIP_ENTRY;
  918.          }
  919.       }
  920.       Rip_stat.vdata[rl->rip_version].output++;
  921.    } else {
  922.       cp = putheader(bp->data,RIPCMD_REQUEST,version, 0);
  923.       Rip_stat.vdata[version].output++;
  924.    }
  925.  
  926.    cp = putentry(cp,0,0,0L,0L,0L,RIP_METRIC_UNREACHABLE);
  927.    send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  928.    return 0;
  929. }
  930.  
  931. /* Write the authentication packet */
  932.  
  933. static char *
  934. putauth(cp,authtype,authpass)
  935. register char *cp;
  936. int16 authtype;
  937. char *authpass;
  938. {
  939.    int x;
  940.  
  941.    cp = put16(cp, 0xFFFF);
  942.    cp = put16(cp, authtype);
  943.  
  944.    /* Put the password in big-endian (network) byte order */
  945.    /* This probably is not the best way to do this, since it */
  946.    /* would hose up on a real big-endian machine.  Oh well */
  947.    /* Something to fix in the future.  Whip me, beat me, make */
  948.    /* me use an Intel micro brain.  -N0POY */
  949.  
  950.    for (x = 0; x < RIP_AUTH_SIZE; x += 4) {
  951.         *cp++ = authpass[x+3];
  952.         *cp++ = authpass[x+2];
  953.         *cp++ = authpass[x+1];
  954.         *cp++ = authpass[x];
  955.    }
  956.    return(cp);
  957. }
  958.  
  959. /* Write the header of a RIP packet */
  960.  
  961. static char *
  962. putheader(cp,command,version,domain)
  963. register char *cp;
  964. char command;
  965. char version;
  966. int16 domain;
  967. {
  968.    *cp++ = command;
  969.    *cp++ = version;
  970.    return put16(cp,domain);
  971. }
  972.  
  973. /* Write a single entry into a rip packet */
  974.  
  975. static char *
  976. putentry(cp,fam,tag,target,targmask,router,metric)
  977. register char *cp;
  978. int16 fam;
  979. int16 tag;
  980. int32 target;
  981. int32 targmask;
  982. int32 router;
  983. int32 metric;
  984.  
  985. {
  986.    cp = put16(cp,fam);
  987.    cp = put16(cp,tag);
  988.    cp = put32(cp,target);
  989.    cp = put32(cp,targmask);
  990.    cp = put32(cp,router);
  991.    return put32(cp,metric);
  992. }
  993.  
  994. /* Check the authentication of RIP-II packets */
  995. int
  996. check_authentication(auth,bpp,header,srcaddr,ifcname,entry)
  997. struct rip_auth *auth;
  998. struct mbuf **bpp;
  999. struct rip_head *header;
  1000. int32 srcaddr;
  1001. char *ifcname;
  1002. struct rip_authenticate *entry;
  1003. {
  1004.    struct rip_auth *rd;
  1005.  
  1006.    for (rd = auth; rd != NULLAUTH; rd = rd->next) {
  1007.       if ((strcmp(ifcname, rd->ifc_name) == 0) ||
  1008.          (strcmp(DEFAULTIFC, rd->ifc_name) == 0)) {
  1009.          if (rd->domain == header->rip_domain) {
  1010.             /* We'll take this domain, check against a NULL password */
  1011.             if (strcmp(rd->rip_auth_code, RIP_NO_AUTH) == 0) {
  1012.                rip_trace(3, "RIP-2 taken due to no password from [%s] domain %d",
  1013.                   inet_ntoa(srcaddr), header->rip_domain);
  1014.                return(TRUE);
  1015.             } else {
  1016.  
  1017.                /* Okay, we need an authentication */
  1018.  
  1019.                if (entry->rip_family != RIP_AF_AUTH) {
  1020.                      /* It doesn't have an authentication packet */
  1021.                      rip_trace(2, "RIP-2 lacking authentication packet from [%s] domain %d",
  1022.                         inet_ntoa(srcaddr), header->rip_domain);
  1023.                      Rip_stat.auth_fail++;
  1024.                      return(FALSE);
  1025.                }
  1026.  
  1027.                if (entry->rip_auth_type != RIP_AUTH_SIMPLE) {
  1028.                      /* Only support simple authentication */
  1029.                      rip_trace(2, "RIP-2 wrong type of authentication from [%s]",
  1030.                         inet_ntoa(srcaddr));
  1031.                      Rip_stat.auth_fail++;
  1032.                      return(FALSE);
  1033.                }
  1034.  
  1035.                if (memcmp(rd->rip_auth_code,entry->rip_auth_str,RIP_AUTH_SIZE) == 0) {
  1036.                   rip_trace(3, "RIP-2 authenticated from [%s] domain %d",
  1037.                      inet_ntoa(srcaddr), header->rip_domain);
  1038.                   return(TRUE);
  1039.                } else {
  1040.                   rip_trace(2, "RIP-2 authentication failed from [%s] domain %d,\n attempted password '%.16s' right password '%.16s'",
  1041.                      inet_ntoa(srcaddr), header->rip_domain, entry->rip_auth_str, rd->rip_auth_code);
  1042.                   Rip_stat.auth_fail++;
  1043.                   return(FALSE);
  1044.                }
  1045.             }
  1046.          }
  1047.       }
  1048.    }
  1049.    /* Didn't find the right routing domain for this packet */
  1050.    rip_trace(3, "RIP-2 domain %d not accepted from [%s]", header->rip_domain,
  1051.       inet_ntoa(srcaddr));
  1052.    Rip_stat.wrong_domain++;
  1053.    return(FALSE);
  1054. }
  1055.  
  1056. /* Route timeout handler. If route has already been marked for deletion
  1057.  * then delete it. Otherwise mark for deletion and restart timer.
  1058.  */
  1059. void
  1060. rt_timeout(s)
  1061. void *s;
  1062. {
  1063.    register struct route *rp = (struct route *)s;
  1064.  
  1065.    stop_timer(&rp->timer);
  1066.    if(rp->metric < RIP_METRIC_UNREACHABLE){
  1067.       rip_trace(5, "RIP:  route to [%s]/%d expired - hold down", inet_ntoa(rp->target),
  1068.          rp->bits);
  1069.       rp->metric = RIP_METRIC_UNREACHABLE;
  1070.       if(dur_timer(&rp->timer) == 0)
  1071.          set_timer(&rp->timer,Rip_ttl*1000L);
  1072.       /* wait 2/3 of timeout before garbage collect */
  1073.       set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  1074.       rp->timer.func = (void *)rt_timeout;
  1075.       rp->timer.arg = (void *)rp;
  1076.       start_timer(&rp->timer);
  1077.       /* Route changed; mark it for triggered update */
  1078.       rp->flags |= RTTRIG;
  1079.       rip_trigger();
  1080.    } else {
  1081.       rip_trace(5, "RIP:  route to [%s]/%d expired - dropped", inet_ntoa(rp->target),
  1082.          rp->bits);
  1083.       rt_drop(rp->target,rp->bits);
  1084.    }
  1085. }
  1086.  
  1087. void
  1088. pullheader(ep,bpp)
  1089. struct rip_head *ep;
  1090. struct mbuf **bpp;
  1091. {
  1092.    ep->rip_cmd = pullchar(bpp);
  1093.    ep->rip_vers = pullchar(bpp);
  1094.    ep->rip_domain = pull16(bpp);
  1095. }
  1096.  
  1097. void
  1098. pullauthentication(ep,bpp)
  1099. struct rip_authenticate *ep;
  1100. struct mbuf **bpp;
  1101. {
  1102.    int x;
  1103.  
  1104.    ep->rip_family = pull16(bpp);
  1105.    ep->rip_auth_type = pull16(bpp);
  1106.    for (x = 0; x < RIP_AUTH_SIZE; x++)
  1107.       ep->rip_auth_str[x] = pullchar(bpp);
  1108. }
  1109.  
  1110. void rip_trace(short level, char *errstr, ...)
  1111. {
  1112.    if (level <= Rip_trace) {
  1113.       char *timestr;
  1114.       time_t timer;
  1115.       va_list argptr;
  1116.  
  1117.       if (Rip_trace_fname != NULLCHAR) {
  1118.          time(&timer);
  1119.          timestr = ctime(&timer);
  1120.          timestr[24] = '\0';
  1121.          Rip_trace_file = fopen(Rip_trace_fname, APPEND_TEXT);
  1122.          fprintf(Rip_trace_file, "%s - ", timestr);
  1123.  
  1124.          va_start(argptr, errstr);
  1125.          vfprintf(Rip_trace_file, errstr, argptr);
  1126.          va_end(argptr);
  1127.          fprintf(Rip_trace_file, "\n");
  1128.          fclose(Rip_trace_file);
  1129.       } else {
  1130.          va_start(argptr, errstr);
  1131.          usvprintf(Curproc->output, errstr, argptr);
  1132.          va_end(argptr);
  1133.          tprintf("\n");
  1134.       }
  1135.    }
  1136. }
  1137.  
  1138.  
  1139. #endif /* RIP */
  1140.  
  1141. void
  1142. pullentry(ep,bpp)
  1143. register struct rip_route *ep;
  1144. struct mbuf **bpp;
  1145. {
  1146.    ep->rip_family = pull16(bpp);
  1147.    ep->rip_tag = pull16(bpp);
  1148.    ep->rip_dest = pull32(bpp);
  1149.    ep->rip_dest_mask = pull32(bpp);
  1150.    ep->rip_router = pull32(bpp);
  1151.    ep->rip_metric = pull32(bpp);
  1152. }
  1153.  
  1154.  
  1155.